home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / PROGRAMM / DB_CLIPP / 0643B.ZIP / LPTX.ASM < prev    next >
Assembly Source File  |  1994-01-01  |  27KB  |  1,023 lines

  1. title LPTx : Line Printer Output Capture Routine
  2. page    66,132
  3. ;-------------------------------------------------------------
  4. ;
  5. ;    MAIN PROGRAM    Version 3.0
  6. ;
  7. ;  (C)    Copyright 1985 by Mark DiVecchio, All Rights Reserved
  8. ;
  9. ; You may use and freely distribute this program for
  10. ; non-commercial applications.
  11. ;
  12. ; Mark C. DiVecchio
  13. ; 9067 Hillery Drive
  14. ; San Diego, CA 92126
  15. ; 619-566-6810
  16. ;-------------------------------------------------------------
  17. ; This program intercepts the BIOS interrupt 17, the line printer
  18. ; interrupt. It will redirect the output of LPT1, LPT2, or LPT3 to a disk
  19. ; file. All three redirects may be active at the same time.
  20. ;
  21. ; This version (3.0) is fully compatible with IBM's PRINT command and
  22. ; hopefully most other print spoolers. I changed the method by which
  23. ; LPTX determines if a resident copy of itself is already in memory.
  24. ;
  25. ; Calling sequence:
  26. ; lptx -1 -o <d:[pathname]filename>
  27. ;
  28. ; where -1 means redirect LPT1, -2 means redirect LPT2, -3 means redirect
  29. ;       LPT3
  30. ;       This option must appear first
  31. ;
  32. ;       -o means start the redirect to file speicfied. If rerouting
  33. ;          is already in progress for the selected line printer,
  34. ;       the old file will be closed first.
  35. ;       (If you do not specify -o but you do specify a line printer,
  36. ;       LPTx will use either the last file name that you gave when
  37. ;       you loaded LPTx or will use the file named LPTX1.LST which it
  38. ;       will create in the root directory 
  39. ;       on the default drive - where x is 1, 2, or 3.)
  40. ;
  41. ;       It is not necessary that you specify the complete path name
  42. ;       for the file. LPTx opens and closes the file each time that it
  43. ;       writes out a block. If you change directories, LPTx will 
  44. ;       be able to find the file because it save the complete path.
  45. ;
  46. ;    -c means close the file and send all furthur output directly to the
  47. ;       line printer.
  48. ;
  49. ; if neither option is specified, LPTx just displays the program status.
  50. ;
  51. ; note: -1, -2, and -3 are mutually exclusive
  52. ;       -o and -c are mutually exclusive
  53. ;
  54. ; examples:
  55. ;
  56. ; lptx                Displays the program status
  57. ;
  58. ; lptx ?            Displays a HELP screen
  59. ;
  60. ; lptx -1            routes LPT1 output to file named
  61. ;                LPTX1.LST on the default drive or the last
  62. ;                named file.
  63. ;
  64. ; lptx -o a:\able.xxx        routes LPT1 output to file named
  65. ;    or            a:\able.xxx. Any open redirection
  66. ; lptx a:\able.xxx        disk file for LPT1 is closed.
  67. ;
  68. ; lptx -2 b:xx.lst        routes LPT2 output to file named
  69. ;                XX.LST in the default directory
  70. ;                on drive B:. Any open redirection
  71. ;                disk file for LPT2 is closed.
  72. ;
  73. ; lptx -3 d:\ab\cd\file.lst    redirects LPT3 output to the file named
  74. ;                file.lst in the directory ab\cd on drive
  75. ;                d:.
  76. ;
  77. ; lptx -c            closes any disk files open for LPT1 and sends
  78. ;    or            the output back to the line printer
  79. ; lptx -1 -c            If no rerouting is taking place to LPT1,
  80. ;                this is    a NOP. LPT2 and LPT3 are not
  81. ;                affected.
  82. ;
  83. ; lptx -2 -c            closes any disk file open for LPT2 and
  84. ;                sends the output back to line printer.
  85. ;                if no rerouting is taking place to LPT2,
  86. ;                this is a NOP. LPT1 and LPT3 are not
  87. ;                affected.
  88. ;
  89. ; By rerouting LPT2 or LPT3 to a disk file, you can in effect have 2 or 3
  90. ; printers on your system. LPT1 can be your physical printer and you can
  91. ; have LPT2 output going to disk. When you redirect LPT2 or LPT3, LPT1 works
  92. ; normally.
  93. ;
  94. ; If you are rerouting to a diskette file, do not remove the diskette
  95. ; once the rerouting starts. I recommend rerouting to a hard disk or
  96. ; a RAM disk.
  97. ;
  98. ; If LPTx encounters any kind of error during the rerouting, it terminates
  99. ; operation and sends output back to the line printer. It does not display
  100. ; anything but beeps the speaker four times. This prevents your currently
  101. ; running program from possibly getting destroyed.
  102. ; An error on LPT1 redirect does not shut down LPT2 or LPT3 redirect.
  103. ;
  104. ; LPTx captures the int 17h interrupt vector. It may not operate correctly
  105. ; with other routines what also intercept that vector.
  106. ;
  107. ; Problems may occur with print spoolers which also take over the int 17h 
  108. ; vector. You can be sure that LPTX works correctly by running LPTX after
  109. ; you have run your print spooler. LPTX will be transparent to the print
  110. ; spooler but your print spooler may not be transparent to LPTX.
  111. ; LPTX works fine with IBM's PRINT command.
  112. ;
  113. ; LPTx also captures the int 24h critical error interrupt vector. This is
  114. ; done only for the period that LPTx is using the disk. This prevents
  115. ; the generation of funny error messages in the middle of other programs
  116. ; that you may be running. (LPTx justs beeps 4 times and clears itself
  117. ; out of way if a disk error occurs).
  118. ;
  119. ; This version of LPTx can redirect all three printers to three different
  120. ; files with all 3 active at the same time.
  121. ;
  122. ; LPTx uses about 7K of memory for the resident data buffers and 
  123. ; interrupt handler.
  124. ;
  125. ; If you modify or find any bugs in this program, I would appreciate
  126. ; it if you would drop me a line with the changes. Use the address
  127. ; above.
  128. ;
  129. if1
  130.     %out Pass 1
  131. else
  132.     %out Pass 2
  133. endif
  134. ;
  135. ;-----------------------------------------------------------------
  136. null        equ    0
  137. off        equ    0
  138. on        equ    1
  139. empty        equ    0
  140. cr        equ    13
  141. lf        equ    10
  142. dollar        equ    '$'
  143. colon        equ    ':'
  144. backslash    equ    '\'
  145. blank        equ    ' '
  146. dash        equ    '-'
  147. dos_call    equ    21h
  148. bufsize        equ    200H    ;size of DMA buffer
  149. display_output    equ    9    ;for DOS call
  150. def_drive    equ    19h
  151. create_file    equ    3Ch
  152. open_file    equ    3Dh
  153. close_file    equ    3Eh
  154. write_file    equ    40h
  155. delete_file    equ    41h
  156. lseek_file    equ    42h
  157. def_path    equ    47h
  158. find_file    equ    4Eh
  159. ;-----------------------------------------------------------------
  160. ;
  161. ; Macros
  162. display    macro    msg
  163.     mov    DX,offset msg
  164.     mov    AH,display_output
  165.     int    dos_call
  166.     endm
  167. ;
  168. ;-----------------------------------------------------------------
  169. ;
  170. p_block    struc
  171. ;
  172. ; data structure - these variables are used only in the
  173. ; memory resident copy of LPTx. BX is set to point to the offset of the
  174. ; allocation of this structure for the selected LPT
  175. ;
  176. active    db    off        ;1 = this LPTx is on, 0 = off
  177. handle    dw    null        ;handle of disk file used by this LPT
  178. ;
  179. ; space for redirection disk file name
  180. ;
  181. filen    db    'a:\lptx'
  182. ptr    db    blank
  183.     db    '.lst',null
  184.     db    '                          '
  185.     db    '                        '
  186. ;
  187. sp_left    dw    empty        ;bytes left in DMA buffer for this LPT
  188. buffer    db    bufsize dup(?)    ;data buffer for this LPT
  189. ;
  190. p_block    ends
  191. ;
  192. ;
  193. ;
  194. ;-----------------------------------------------------------------
  195. ;
  196. subttl    Main Code
  197. page
  198. %out Assembling CODE Segment
  199. cseg    segment para public 'CODE'
  200.     assume  CS:cseg,DS:nothing,SS:nothing
  201. ;
  202.     org    100h
  203. lptx:    jmp    l_start
  204. id    dw    03579h        ;unique ID for this program
  205. ;
  206. ; What follows is three allocations of the Structure p_block
  207. ; One for each line printer that we can support.
  208. ; With this, all three line printers have DMA buffers and flag
  209. ; variables.
  210. ; BX is used to point to the offset of the allocation currently in use
  211. ;
  212. ; Line printer 1
  213. lpt1    p_block    <,,,'1'>
  214. ;
  215. ; Line printer 2
  216. lpt2    p_block    <,,,'2'>
  217. ;
  218. ; Line printer 3
  219. lpt3    p_block    <,,,'3'>
  220. ;
  221. lptxe    db    7,7,7,7,dollar    ;ring bell four times
  222. crit_flag    db    0    ;set to one if critical error occured
  223. off_crit    dw    0    ;save old critical error address
  224. seg_crit    dw    0
  225. ;
  226. dosstk    db    0C80H dup(?)    ;place to save INT 21H's stack
  227. stksav    dd    0        ;caller's stack EA
  228.     db    64 dup('STACK   ')
  229. stk    equ    this byte
  230. ;-----------------------------------------------------------------
  231. ;
  232. ; Interrupt handler
  233. ;
  234. prt_int:
  235.     cmp    DX,0F0Fh    ;my flag to detect that LPTX is
  236.                 ;already loaded and alive.
  237.     jne    reg_call    ;This is a regular print call
  238.     jmp    ret_ack
  239. reg_call:            ; set up BX
  240.     push    BX
  241.     cmp    DX,0        ;lpt1?
  242.     jne    chk_lpt2    ;no
  243.     mov    BX,offset lpt1    ;offset to LPT1
  244.     jmp    short bx_set
  245. chk_lpt2:
  246.     cmp    DX,1        ;lpt2?
  247.     jne    chk_lpt3    ;no
  248.     mov    BX,offset lpt2    ;offset to LPT2
  249.     jmp    short bx_set
  250. chk_lpt3:
  251.     cmp    DX,2        ;lpt3?
  252.     jne    ill_ptr        ;no - bad printer number
  253.     mov    BX,offset lpt3    ;offset to LPT3
  254. bx_set:
  255.     cmp    CS:[BX].active,off    ;are we active?
  256.     je    sleep        ;no
  257.     cmp    AH,1        ;initialize call?
  258.     je    do_nix        ;yes    
  259.     cmp    AH,2        ;status call?
  260.     je    do_nix        ;yes
  261.     cmp    AH,0        ;print call?
  262.     jne    do_nix        ;no
  263.     jmp    prt_it        ;we are active
  264. do_nix:    mov    AH,90h        ;Ready Status
  265.     pop    BX
  266.     iret
  267. ;
  268. ill_ptr:mov    AH,0
  269.     pop    BX
  270.     iret            ;return with error status
  271. ;
  272. ret_ack:            ;return acknowledgement that I'm here
  273.     mov    DX,05555h
  274.     mov    AX,0AAAAh
  275.     push    CS        ;now set up ES to point to the resident
  276.     pop    ES        ; data area
  277.     iret
  278. ;
  279. sleep:    pop    BX        ;restore BX before we go to sleep
  280.     db    0EAh        ;jump immediate to next handler
  281. oldint    dd            ;address of old int 17 routine
  282. ;-----------------------------------------------------------------
  283. ;
  284. ; Start the print process
  285. ;
  286. prt_it:    push    AX
  287.     push    BX
  288.     push    CX
  289.     push    DX
  290.     push    DS
  291.     push    ES
  292.     push    SI
  293.     push    DI
  294.     push    BP
  295.                 ; DS is used as the segment register
  296.                 ; for all data during the interrupt
  297. ;
  298.     push    CS
  299.     pop    DS        ;set up DS
  300. ;
  301.     cli
  302.     mov    SI,SS
  303.     mov    word ptr stksav+2,SI    ;save caller's stack
  304.     mov    SI,SP
  305.     mov    word ptr stksav,SI
  306.     mov    SI,CS
  307.     mov    SS,SI            ;give me new bigger stack
  308.     mov    SI,offset stk
  309.     mov    SP,SI
  310.     sti
  311.  
  312.     call    prnt            ;print the character
  313. ;
  314.     cli
  315.     mov    SI,word ptr stksav
  316.     mov    SP,SI            ;restore caller's stack
  317.     mov    SI,word ptr stksav+2
  318.     mov    SS,SI
  319.     sti
  320. ;
  321.     pop    BP
  322.     pop    DI
  323.     pop    SI
  324.     pop    ES
  325.     pop    DS
  326.     pop    DX
  327.     pop    CX
  328.     pop    BX
  329.     pop    AX
  330.     jmp    do_nix
  331. ;-----------------------------------------------------------------
  332. ;
  333. ; Critical Error Handler
  334. ;
  335. crit_int:                ;got critical error
  336.     mov    CS:crit_flag,on        ; set flag
  337.     mov    AL,0            ;tells DOS to ignore the
  338.     iret                ;error
  339. ;-----------------------------------------------------------------
  340. ;
  341. ; Print a character in AL
  342. ;
  343. prnt    proc    near
  344.     cmp    DS:[BX].active,off
  345.     je    prtext            ;nothing there?
  346.     push    AX
  347.     cmp    DS:[BX].sp_left,bufsize    ;buffer full
  348.     jne    intadd            ;no
  349.     call    flush            ;yes, flush buffer
  350. intadd:    pop    AX
  351.     mov    DI,BX            ;offset of this printer's allocation
  352.     add    DI,offset buffer    ;add in offset of buffer
  353.     add    DI,DS:[BX].sp_left    ;add in current byte count
  354.     mov    DS:[DI],AL        ;stuff it
  355.     inc    DS:[BX].sp_left
  356. prtext:    ret                ;done
  357. prnt    endp
  358. ;
  359. ;    Flush print buffer to disk file
  360. ;
  361. flush    proc    near
  362.     cmp    DS:[BX].sp_left,empty    ;buffer non-empty?
  363.     jne    flush_buf        ;empty, skip it
  364.     ret                ;exit
  365. flush_buf:
  366.     mov    DS:[BX].sp_left,empty    ;else, reset it
  367. ;
  368.     push    ES
  369.     push    DS
  370. ;
  371. ;    Preserve a chunk of DOS 2.0 across int 21h
  372. ;    See PC Technical reference manual page D-7 for hint.
  373. ;    It comments that only DOS calls 0 - 12 can be safely made
  374. ;    from an interrupt handler. "Use of any other call will
  375. ;    destroy the DOS stack and will leave DOS in an 
  376. ;    unpredictable state." What we do here is save and restore
  377. ;    3200 bytes of the DOS stack and restore it later. We only
  378. ;    do it for the DOS stack. If this was invoked by a user
  379. ;    program, we won't save the DOS stack or the user stack.
  380. ;    It is not necessary.
  381. ;
  382.     mov    AX,word ptr DS:stksav+2    ;get callers stack segment
  383.     cmp    AX,0100h        ; is it DOS?
  384.     ja    flusha            ;no, don;t bother to save it
  385.     mov    AX,DS            ;copy to my segment
  386.     mov    ES,AX
  387.     mov    AX,word ptr DS:stksav+2    ;copying from caller's stack
  388.     mov    DS,AX
  389.     mov    SI,0            ;offset into DOS's stack
  390.     mov    DI,offset dosstk
  391.     mov    CX,0C80h        ;length to save
  392.     cld
  393.     rep    movsb            ;copy DOS's stack
  394. ;
  395.     pop    DS
  396.     push    DS
  397. ;
  398. flusha:
  399. ;
  400.     push    AX            ;save the character
  401.     push    BX
  402.     push    ES
  403.     mov    AX,3524h        ;get old critical error vector
  404.     int    dos_call
  405.     mov    DS:off_crit,BX
  406.     mov    DS:seg_crit,ES
  407.     mov    DX,offset crit_int
  408.     mov    AX,2524h    
  409.     int    dos_call            ;trap critical error vector
  410.     mov    DS:crit_flag,off        ;clear critical error flag
  411.     pop    ES
  412.     pop    BX
  413.     pop    AX
  414. ;                    open file
  415.     mov    DX,BX
  416.     add    DX,offset filen        ;filename
  417.     mov    AL,1            ;open for writing
  418.     mov    AH,open_file
  419.     int    dos_call
  420.     mov    DS:[BX].handle,AX    ;file handle
  421.     jc    flush_err        ;error
  422.     cmp    DS:crit_flag,on        ;critical error?
  423.     je    flush_err        ;yes
  424. ;
  425.     push    BX
  426.     mov    AH,lseek_file
  427.     mov    AL,2            ;end of file
  428.     mov    CX,0            ;offset 0
  429.     mov    DX,0
  430.     mov    BX,DS:[BX].handle
  431.     int    dos_call
  432.     pop    BX
  433.     jc    flush_err        ;some seek error
  434.     cmp    DS:crit_flag,on        ;critical error?
  435.     je    flush_err        ;yes
  436. ;
  437.     mov    CX,bufsize        ;buffer length
  438.     mov    DX,BX            ;offset of structure allocation
  439.     add    DX,offset buffer    ;add offset of buffer within the
  440.                     ;    allocation
  441.     push    BX
  442.     mov    AH,write_file
  443.     mov    BX,DS:[BX].handle    ;file handle
  444.     int    dos_call        ;buffer address is DS:DX
  445.     pop    BX
  446.     jnc    flush_ok
  447.     cmp    DS:crit_flag,on        ;critical error?
  448.     je    flush_err        ;yes
  449.     cmp    AX,bufsize        ;did DOS write it all?
  450.     je    flush_ok        ;yes
  451. ;
  452. flush_err:
  453.     display lptxe            ;ring bell
  454.     mov    DS:[BX].active,off    ;turn us off
  455.     mov    DS:crit_flag,off    ;clear error flag
  456. ;                    ;then try to close the file
  457. ;                    ;to save what we can
  458. flush_ok:
  459.     push    BX
  460.     mov    BX,DS:[BX].handle
  461.     mov    AH,close_file        ;close the file
  462.     int    dos_call
  463.     pop    BX
  464. ;
  465. flush_exit:
  466.     pop    DS
  467.     pop    ES
  468. ;
  469.     push    DS
  470.     lds    DX,dword ptr DS:off_crit
  471.     mov    AX,2524h        ;restore critical error vector
  472.     int    dos_call
  473.     pop    DS
  474. ;
  475.     mov    AX,word ptr DS:stksav+2    ;copying to DOS's workarea
  476.     cmp    AX,100H
  477.     ja    flushe            ;must be DOS's segment
  478.     push    ES
  479.     mov    ES,AX
  480.     mov    DI,0            ;restore data areas
  481.     mov    SI,offset dosstk
  482.     mov    CX,0C80H        ;length to restore
  483.     cld
  484.     rep    movsb            ;copy DOS's stack
  485.     pop    ES            ;restore ES
  486. ;
  487. flushe:    ret
  488. flush    endp
  489. ;
  490. end_res    db    0
  491. ;
  492. ;
  493. ; This is the end of the memory resident portion of LPTx
  494. ;
  495. ;
  496. ;--------------------------------------------------------------------
  497. ;--------------------------------------------------------------------
  498. ;--------------------------------------------------------------------
  499. ;
  500. ; all following data is in the Code Segment
  501. ;
  502. mach_type    db    0
  503. save_psp    dw    0
  504. DOS_version    db    0        ;Major Version Number
  505.         db    0        ;Minor Version Number
  506. drive        db    0        ;default drive number 0=A etc.
  507. flag_27        db    0        ; 1=make this copy resident
  508. wrong_dos    db    'DOS 2.0 or later required for LPTx',lf,cr,dollar
  509.  
  510. up_msg        db    'LPTx - Line Printer Redirection Program - V3.00'
  511.         db    lf,cr,'   Copyright 1985 Mark C. DiVecchio',lf,cr
  512.         db    dollar
  513. resident    db    lf,cr,'Resident Portion of LPTx Loaded',lf,lf,cr
  514.         db    dollar
  515. lptx_err_3    db    'Could not delete file',lf,cr,dollar
  516. lptx_over    db    cr,lf,'File already exists. Do you want to overwrite '
  517.         db    'it? (y or n)  :$'
  518. lptx_nc        db    'File selection canceled',cr,lf,dollar
  519. lptx_del    db    'File is being overwritten',lf,cr,dollar
  520. lptx_cr        db    lf,cr,dollar
  521. lptx_bad    db    'Invalid Option',lf,cr
  522.         db    'Calling sequence:',lf,cr
  523.         db    'lptx {-1,-2,-3} {-c -o <d:[pathname]filename>}'
  524.         db    lf,cr,dollar
  525. lptx_on        db    lf,cr,'Redirection started. Disk file opened.'
  526.         db    lf,cr,dollar
  527. lptx_off    db    lf,cr,'Redirection ended. Disk file closed.'
  528.         db    lf,cr,dollar
  529. lptx_creat    db    'Could not create the disk file',lf,cr,dollar
  530. ;
  531. ; HELP screen
  532. ;
  533. help_msg    db    lf,cr,'Calling sequence : ',lf,lf,cr
  534.         db    'LPTX -p -f <[d:][\pathname\pathname]filename>'
  535.         db    lf,lf,cr
  536.         db    '    where  p = printer number : 1, 2, or 3',lf,cr
  537.         db    '           f = function : o for open a print file'
  538.         db    lf,cr
  539.         db    '                          c for close a print file'
  540.         db    lf,cr
  541.         db    '           drive letter & pathname are optional'
  542.         db    lf,cr
  543.         db    '    defaults : p = 1',lf,cr
  544.         db    '               f = o',lf,cr,dollar
  545. ;
  546. ; messages for STAT proc
  547. ;
  548. stat_stat    db    cr,lf,'LPTx Status :',cr,lf,dollar
  549. stat_lp        db    'lpt'
  550. stat_ptr    db    ' : $'
  551. stat_off    db    ' not redirected',cr,lf,dollar
  552. stat_dir    db    ' redirected to disk file '
  553. stat_fn        db    60 dup (blank)
  554. ;
  555. ;
  556. yn_max        db    2    ;max # of char
  557. yn_act        db    0
  558. yn_in        db    2 dup (0)
  559. ;
  560. ;--------------------------------------------------------------------
  561. ;
  562. ; This is the main routine which is executed each time that LPTx is 
  563. ; called. In this routine, DS points to the data segment which is
  564. ; transient. ES points to the data segment which is permanently
  565. ; resident. ES:BX points to the data structure for the selected 
  566. ; line printer, 1, 2, or 3.
  567. ; The offsets are the same for both. If this is the first
  568. ; time that LPTx is run, then ES=DS.
  569. ;
  570. l_start:
  571.     sti        ;interrupts on
  572.     push    DS    ;Save DS
  573.     xor    AX,AX    ;clear AX for return IP
  574.     push    AX    ;put 0 on stack
  575. ;
  576. ;to check for machine type look at
  577. ; F000:FFFE
  578. ;    = FF    IBM PC
  579. ;    = FE    IBM XT
  580. ;    = FD    IBM PCjr
  581. ;    = FC    IBM PC AT
  582. ;
  583.     mov    AX,0F000h
  584.     mov    ES,AX
  585.     mov    BX,0FFFEh
  586.     mov    CL,ES:[BX]    ;get machine type
  587.     mov    mach_type,CL    ;save machine type
  588.     mov    save_psp,DS    ;segment address of PSP
  589. ;
  590. ; get the DOS version number
  591. ; returns zero for pre DOS 2.0 releases
  592.     mov    AH,30h
  593.     int    dos_call    ;call DOS
  594.     mov    word ptr DOS_version,AX    
  595. ;
  596.     cmp    DOS_version,2    ;is it DOS 2.+
  597.     jge    dos_ok        ;yes
  598.     display    wrong_dos    ;print error message
  599.     mov    AH,0
  600.     int    dos_call    ;terminate
  601. dos_ok:
  602. ;
  603.     mov    AH,def_drive    ;get current default drive
  604.     int    dos_call
  605.     mov    drive,AL    ;save the drive number
  606.     display    up_msg        ;print program ID
  607. ;
  608. ; get old interrupt handler
  609. ;
  610.     mov    flag_27,off    ;to not make resident
  611.     mov    AL,17h        ;get current vector address
  612.     mov    AH,35h
  613.     int    dos_call
  614.     mov    word ptr oldint,BX
  615.     mov    word ptr oldint[2],ES    ;save it for later use
  616. ;
  617. ; are we already resident in memory?
  618. ;
  619.     mov    DX,0F0Fh        ;check if LPTX is already resident
  620.     mov    AX,2            ;get status
  621.     int    17h            ;call int 17h - BIOS
  622.     cmp    DX,5555h        ;my handler sets DX to 5555h
  623.                     ;and sets ES 
  624.     je    in_core            ;yes - ES has segment address
  625.     mov    flag_27,on        ;to make this copy resident
  626.     push    CS
  627.     pop    ES            ;set ES to CS for segment address
  628. ;
  629.     mov    AL,drive
  630.     add    AL,'a'            ;make it a letter
  631.     mov    BX,offset lpt1
  632.     mov    ES:[BX].filen,AL    ;put it into the filename
  633.     mov    BX,offset lpt2
  634.     mov    ES:[BX].filen,AL    ;put it into the filename
  635.     mov    BX,offset lpt3
  636.     mov    ES:[BX].filen,AL    ;put it into the filename
  637. in_core:                ;ES is ok
  638. ; ----------------------------------------------------
  639. ; ES now points to resident data area
  640. ;
  641. ; set up ES:BX to point to default data structure
  642. ;
  643.     mov    BX,offset lpt1        ;offset - default to LPT1
  644. ;
  645. ;get options and file name
  646. ;scan input line for line printer number
  647. ;
  648.     mov    SI,81h            ;starting offset
  649.     mov    CL,DS:80h        ;length of input line
  650.     mov    CH,0
  651.     cmp    CX,0            ;nothing?
  652.     jne    inp_lp            ;no
  653.     jmp    nor_exit        ;yes, then just display status
  654. inp_lp:
  655.     cmp    byte ptr DS:[SI],'?'    ;a ?  ?
  656.     jne    cont_scan        ;no
  657.     jmp    help            ;yes - go show help data
  658. cont_scan:
  659.     cmp    byte ptr DS:[SI],dash    ;a dash ?
  660.     je    got_opt            ;yes
  661.     cmp    byte ptr DS:[SI],cr    ;a carriage return?
  662.     je    scan_done        ;yes
  663.     cmp    byte ptr DS:[SI],blank    ;a blank?
  664.     je    inp_ret            ;yes
  665.     jmp    no_b            ;assume that we got a file name
  666.                     ;without the -o option
  667. inp_ret:
  668.     inc    SI            ;ignore blanks
  669.     loop    inp_lp            ;continue to scan
  670. ;
  671. ; scan of whole line is complete, if options were not found, we
  672. ; use defaults : LPT1 and file LPTX1.LST on the default drive.
  673. ; note : at least one option must be specified
  674. ;
  675. scan_done:
  676.     jmp    lptx_make        ;go create the file
  677. ;
  678. got_opt:                ;we got an option
  679.     inc    SI            ;to option
  680.     cmp    byte ptr DS:[SI],'1'    ;LPT1?
  681.     jne    chk_2
  682.     mov    BX,offset lpt1        ;offset from ES
  683.     jmp    short inp_ret
  684. chk_2:    cmp    byte ptr DS:[SI],'2'    ;LPT2?
  685.     jne    chk_3
  686.     mov    BX,offset lpt2        ;offset from ES
  687.     jmp    short inp_ret
  688. chk_3:    cmp    byte ptr DS:[SI],'3'    ;LPT3?
  689.     jne    chk_fil
  690.     mov    BX,offset lpt3        ;offset from ES
  691.     jmp    short inp_ret
  692. chk_fil:                ;is it file?
  693.     cmp    byte ptr DS:[SI],'o'    ;open a file
  694.     je    file_op            ;yes
  695.     cmp    byte ptr DS:[SI],'c'    ;close a file
  696.     je    file_cl            ;yes
  697.     display    lptx_bad        ;incorrect option
  698.     jmp    nor_ex
  699. ;
  700. file_cl:                ;close the output file
  701.     cmp    ES:[BX].active,on    ;are we active?
  702.     jne    no_close        ;no
  703.     mov    AL,1AH            ;CTRL-Z
  704.     mov    word ptr ES:stksav+2,AX    ;do this so that prnt does
  705.                     ;not bother to save the DOS stack
  706.     push    DS
  707.     push    ES
  708.     pop    DS            ;set DS to point to resident
  709.                     ;data segment
  710.     call    prnt            ;print end of file mark
  711.     call    flush            ;flush out write buffer
  712.     pop    DS            ;restore DS
  713. ;
  714.     mov    ES:[BX].active,off    ;make us inactive
  715.     display lptx_off        ;redirection off message
  716. no_close:
  717.     jmp    nor_exit        ;nothing to close so exit
  718. file_op:                ;open a file for output
  719. ;get the file name
  720.     inc    SI            ;to next chracter
  721.     cmp    byte ptr DS:[SI],blank    ;a blank?
  722.     jne    no_b            ;no
  723.     inc    SI            ;skip over blank
  724. no_b:
  725. ; at this point, we have found a new file name. We close the old
  726. ; file if one was open
  727.     cmp    ES:[BX].active,on    ;are we active?
  728.     jne    no_cl            ;no
  729.     mov    AL,1AH            ;CTRL-Z
  730.     mov    word ptr ES:stksav+2,AX    ;do this so that prnt does
  731.                     ;not bother to save the DOS stack
  732.     push    DS
  733.     push    ES
  734.     pop    DS            ;set DS to point to resident
  735.                     ;data segment
  736.     call    prnt            ;print end of file mark
  737.     call    flush            ;flush out write buffer
  738.     pop    DS            ;restore DS
  739. ;
  740.     mov    ES:[BX].active,off    ;make us inactive
  741.     display lptx_off        ;redirection off message
  742. no_cl:
  743.     mov    DI,BX            ;base of structure
  744.     add    DI,offset filen        ;add offset of destination
  745. ;
  746.     push    SI            ;save pointer to file name
  747. ; search for a drive letter
  748.     inc    SI            ;should point to a colon if
  749.                     ;one is there
  750.     cmp    byte ptr [SI],colon    ;?
  751.     je    got_drive        ;yes
  752. get_drive:
  753.     mov    AL,drive        ;get drive letter
  754.     add    AL,'a'            ;make it a letter
  755.     mov    ES:[DI],AL        ;put it in file name
  756.     inc    DI
  757.     mov    byte ptr ES:[DI],colon    ;put in a colon
  758.     inc    DI
  759.     jmp    path_search
  760. got_drive:
  761.     pop    SI            ;move pointer back to start
  762.     mov    AL,[SI]            ;get the given drive
  763.     mov    ES:[DI],AL        ;move it
  764.     sub    AL,'a'            ;make it a number
  765.     mov    drive,AL        ;save the drive number
  766.     inc    SI
  767.     inc    DI
  768.     mov    byte ptr ES:[DI],colon
  769.     inc    DI
  770.     inc    SI
  771.     push    SI            ;save new start pointer
  772. path_search:
  773. ; now search for a backslash which says that a pathname was given
  774. bk_s_lp:cmp    byte ptr [SI],backslash
  775.     je    got_path        ;a path
  776.     cmp    byte ptr [SI],cr    ;end of the file name?
  777.     je    get_path        ;yes with no path
  778.     inc    SI
  779.     jmp    short bk_s_lp            ;loop
  780. get_path:
  781.     mov    byte ptr ES:[DI],backslash    ;create the path
  782.     inc    DI
  783.     mov    DL,drive        ;the current drive
  784.     inc    DL            ;bump it for DOS
  785.     push    DS
  786.     push    ES
  787.     pop    DS            ;set up DS for DOS
  788.     mov    SI,DI            ;set up SI for pathname
  789.     mov    AH,def_path        ;get current directory
  790.     int    dos_call        ;path goes into DS:SI
  791.     pop    DS            ;restore DS
  792.     cmp    byte ptr ES:[SI],null    ;null path?
  793.     je    null_path        ;yes - root directory
  794. path_lp:                ;now find the end of the string
  795.     cmp    byte ptr ES:[SI],null    ;null byte marks end of pathname
  796.     je    end_path        ;now append the file name
  797.     inc    SI
  798.     jmp    short path_lp
  799. end_path:
  800.     mov    byte ptr ES:[SI],backslash
  801.     inc    SI
  802. null_path:
  803.     mov    DI,SI            ;DI is destination
  804. got_path:
  805.     pop    SI            ;restore source of filename
  806. ; pick up everything to next blank
  807. get_lp:
  808.     mov    AL,DS:[SI]        ;character
  809.     mov    ES:[DI],AL        ;put it away
  810.     cmp    AL,cr            ;was it a Carriage Return?
  811.     je    end_line
  812.     cmp    AL,blank        ;was it a space?
  813.     je    end_line
  814.     inc    SI
  815.     inc    DI
  816.     jmp    short get_lp        ;no so get next character
  817. end_line:
  818.     mov    byte ptr ES:[DI],null    ;zero out the CR or blank
  819.                     ;at the end of the filename
  820.                     ;it becomes an ASCIIZ string
  821.     sub    DI,BX            ;now take out the base and
  822.     cmp    DI,offset filen        ; make sure that we got something
  823.     jne    lptx_make        ;file name was ok
  824.     display lptx_creat        ;could not understand the file name
  825.     jmp    nor_exit        ;don't stay resident
  826. ;
  827. nor_ex:    jmp    nor_exit
  828.  
  829. lptx_make:
  830. ;
  831. ; default DTA used by Find File is set by DOS to an offset of
  832. ; 80h into this program's Program Segment Prefix
  833. ;
  834.     push    DS
  835.     push    ES
  836.     pop    DS            ;uses DS:DX
  837.     mov    DX,BX
  838.     add    DX,offset filen        ;file name
  839.     mov    AH,find_file
  840.     mov    CX,0            ;normal files only
  841.     int    dos_call        ;find first match
  842.     pop    DS
  843.     jnc    lptx_d            ;file was found
  844.     jmp    lptx_create        ;not there - which is ok
  845. ;file already exists
  846. lptx_d:    display lptx_over
  847.     mov    DX,offset yn_max;input buffer
  848.     mov    AH,0AH
  849.     int    dos_call
  850.     cmp    yn_act,0        ;anything typed?
  851.     display    lptx_cr
  852.     je    lptx_x            ;no - exit
  853.     cmp    yn_in,'y'        ;a yes?
  854.     je    lptx_d_yes        ;yes
  855.     cmp    yn_in,'Y'        ;a yes?
  856.     je    lptx_d_yes        ;yes
  857. lptx_x:    display    lptx_nc
  858.     jmp    nor_exit    ;all done if we can't overwrite
  859.                 ;see if we should abort the host
  860. lptx_d_yes:
  861.     display lptx_del
  862. ;
  863.     push    DS
  864.     push    ES
  865.     pop    DS            ;uses DS:DX
  866.     mov    DX,BX
  867.     add    DX,offset filen        ;file name
  868.     mov    AH,delete_file
  869.     int    dos_call        ;delete file
  870.     pop    DS
  871.     jnc    lptx_create        ;ok its gone
  872.     display lptx_err_3        ;can't delete it
  873.     jmp    nor_exit
  874. ;
  875. ;
  876. lptx_create:
  877. ;
  878. ; create the file
  879.     push    DS
  880.     push    ES
  881.     pop    DS            ;uses DS:DX
  882.     mov    DX,BX            ;base of this LPT's structure
  883.     add    DX,offset filen        ;file name
  884.     mov    AH,create_file
  885.     mov    CX,0            ;normal files only
  886.     int    dos_call            ;find first match
  887.     pop    DS
  888.     jnc    creat_ok
  889.     display lptx_creat        ;could not create the file
  890.     jmp    nor_exit        ;don't stay resident
  891. ;
  892. creat_ok:                ;now close the file
  893.     push    BX
  894.     mov    BX,AX            ;AX was loaded by the create file
  895.                     ;    call
  896.     mov    AH,close_file        ;close the file
  897.     int    dos_call
  898.     pop    BX
  899. ;
  900.     display    lptx_on
  901. ; set the program up for writing
  902.     mov    ES:[BX].sp_left,empty    ;set buffer empty
  903.     mov    ES:[BX].active,on    ;set us on
  904. ;
  905.     cmp    flag_27,on        ;make this one resident?
  906.     jne    nor_exit        ;no
  907. ;
  908. ; Now set LPTX up as the new int 17h interrupt handler
  909. ;
  910.     mov    AH,25h            ;set interrupt vector
  911.     mov    AL,17h            ;BIOS printer
  912.     mov    DX,offset prt_int
  913.     int    dos_call
  914.     display resident        ;resident loaded message
  915.     call    stat            ;display status
  916.     mov    DX,offset end_res
  917.     int    27h            ;terminate but stay resident
  918. ;
  919. ; HELP printer
  920. ;
  921. help:    display    help_msg        ;display the HELP screen
  922.     jmp    short nor_exit
  923. ;
  924. ; Normal exit for transient copy of LPTX
  925. ;
  926. nor_exit:
  927.     call    stat            ;display status
  928.     mov    AH,0
  929.     int    dos_call        ;terminate
  930. ;------------------------------------------------------------------------
  931. ;
  932. ; displays the status of each of the three line printers
  933. ;
  934. stat    proc    near
  935. ; display each LPTx with a message "not redirected"
  936. ;            or redirected to <filename>
  937.     display    stat_stat
  938. stat_1:
  939.     mov    BX,offset lpt1        ;first printer
  940.     mov    stat_ptr,'1'
  941.     display    stat_lp
  942.     cmp    ES:[BX].active,on    ;are we active?
  943.     je    stat_1_a        ;yes
  944.     display stat_off
  945.     jmp    short stat_2
  946. stat_1_a:
  947.     mov    SI,BX            ;base
  948.     add    SI,offset filen        ;offset
  949.     mov    DI,offset stat_fn
  950. stat_1_lp:
  951.     mov    AL,ES:[SI]
  952.     mov    [DI],AL
  953.     inc    SI
  954.     inc    DI
  955.     cmp    AL,null            ;loop till a null byte is found
  956.     jne    stat_1_lp
  957.     mov    byte ptr [DI],cr
  958.     inc    DI
  959.     mov    byte ptr [DI],lf
  960.     inc    DI
  961.     mov    byte ptr [DI],dollar
  962.     display stat_dir        ;display file name
  963. ;
  964. stat_2:
  965.     mov    BX,offset lpt2        ;second printer
  966.     mov    stat_ptr,'2'
  967.     display    stat_lp
  968.     cmp    ES:[BX].active,on    ;are we active?
  969.     je    stat_2_a        ;yes
  970.     display stat_off
  971.     jmp    short stat_3
  972. stat_2_a:
  973.     mov    SI,BX            ;base
  974.     add    SI,offset filen        ;offset
  975.     mov    DI,offset stat_fn
  976. stat_2_lp:
  977.     mov    AL,ES:[SI]
  978.     mov    [DI],AL
  979.     inc    SI
  980.     inc    DI
  981.     cmp    AL,null            ;loop till a null byte is found
  982.     jne    stat_2_lp
  983.     mov    byte ptr [DI],cr
  984.     inc    DI
  985.     mov    byte ptr [DI],lf
  986.     inc    DI
  987.     mov    byte ptr [DI],dollar
  988.     display stat_dir        ;display file name
  989. ;
  990. stat_3:
  991.     mov    BX,offset lpt3        ;third printer
  992.     mov    stat_ptr,'3'
  993.     display    stat_lp
  994.     cmp    ES:[BX].active,on    ;are we active?
  995.     je    stat_3_a        ;yes
  996.     display stat_off
  997.     jmp    short stat_done
  998. stat_3_a:
  999.     mov    SI,BX            ;base
  1000.     add    SI,offset filen        ;offset
  1001.     mov    DI,offset stat_fn
  1002. stat_3_lp:
  1003.     mov    AL,ES:[SI]
  1004.     mov    [DI],AL
  1005.     inc    SI
  1006.     inc    DI
  1007.     cmp    AL,null            ;loop till a null byte is found
  1008.     jne    stat_3_lp
  1009.     mov    byte ptr [DI],cr
  1010.     inc    DI
  1011.     mov    byte ptr [DI],lf
  1012.     inc    DI
  1013.     mov    byte ptr [DI],dollar
  1014.     display stat_dir        ;display file name
  1015. ;
  1016. stat_done:
  1017.     ret
  1018. stat    endp
  1019. ;
  1020. cseg    ends
  1021. %out EOF
  1022.     end    lptx
  1023.